package main

import "fmt"

/*
在前面的Usb接口案例做改进：
给Phone结构体增加一个特有的方法call()，当Usb接口接收的是Phone变量时，还需要调用call方法
*/
//第一个实践
//声明/定义一个接口
type Usb interface {
	//声明了两个没有实现的方法
	Start()
	Stop()
}
type Phone struct {
	name string
}

//让Phone实现Usb接口的方法
func (p Phone) Start() {
	fmt.Println(p.name, "手机开始工作...")
}
func (p Phone) Stop() {
	fmt.Println(p.name, "手机停止工作...")
}
func (p Phone) Call() {
	fmt.Println(p.name, "手机正在打电话...")
}

//让Camera实现Usb接口的方法
type Camera struct {
	name string
}

//让Camera实现Usb接口的方法
func (c Camera) Start() {
	fmt.Println(c.name, "相机开始工作...")
}
func (c Camera) Stop() {
	fmt.Println(c.name, "相机停止工作...")
}

//计算机
type Computer struct {
}

//编写一个方法Working，接收一个Usb接口类型变量
//只要是实现了Usb接口，所谓实现Usb接口，就是指实现了Usb接口声明的所有的方法
func (c Computer) Working(usb Usb) { //usb变量会根据传入的实参，来判断到底是Phone还是Camera，usb接口变量就体现出多态的特点
	//通过usb接口变量来调用Start和Stop方法
	usb.Start()
	//如果usb是指向Phone结构体变量，则还需要调用Call方法
	if phone, ok := usb.(Phone); ok == true {
		phone.Call()
	}
	usb.Stop()
}

//第二个实践
//编写一个函数，可以判断输入的参数是什么类型
func TypeJudge(items ...interface{}) {
	for index, x := range items {
		switch x.(type) {
		case bool:
			fmt.Printf("第%v个参数是bool类型，值是%v\n", index, x)
		case float32:
			fmt.Printf("第%v个参数是float32类型，值是%v\n", index, x)
		case float64:
			fmt.Printf("第%v个参数是float64类型，值是%v\n", index, x)
		case int, int32, int64:
			fmt.Printf("第%v个参数是整数类型，值是%v\n", index, x)
		case string:
			fmt.Printf("第%v个参数是string类型，值是%v\n", index, x)
		case Student:
			fmt.Printf("第%v个参数是Student类型，值是%v\n", index, x)
		case *Student:
			fmt.Printf("第%v个参数是*Student类型，值是%v\n", index, x)
		default:
			fmt.Printf("第%v个参数的类型不确定，值是%v\n", index, x)
		}
	}
}

type Student struct {
}

func main() {
	//定义一个Usb接口数组，可以存放Phone和Camera的结构体变量
	//这里就体现出多态数组
	computer := Computer{}
	var usbArr [3]Usb
	usbArr[0] = Phone{"vivo"}
	usbArr[1] = Phone{"小米"}
	usbArr[2] = Camera{"尼康"}
	fmt.Println(usbArr)

	//遍历usbArr
	//Phone还有一个特有的方法call()，请遍历usb数组，如果是Phone变量
	//除了调用Usb接口声明的方法外，还需要调用Phone特有方法call => 类型断言
	for _, v := range usbArr {
		computer.Working(v)
		fmt.Println()
	}
	fmt.Println()
	//第二个实践
	var n1 float32 = 1.1
	var n2 float64 = 2.3
	var n3 int32 = 30
	var name string = "tom"
	address := "北京"
	n4 := 300
	stu1 := Student{}
	stu2 := &Student{}
	TypeJudge(n1, n2, n3, name, address, n4, stu1, stu2)
}
